 #define _ftp_
 #include "controls.h"
 #include "common.h"
 #include "ftp.h"
 #include "netpad.h"
 #include "util.h"

 extern wxCondition * m_condition;
 extern wxMutex     * m_mutex;
 
 FTP::FTP( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) 
    : wxPanel( parent, id, pos, size, style )
 {
   sz4 = new wxBoxSizer(wxVERTICAL);

   split = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);

   split->Connect(wxEVT_IDLE, wxIdleEventHandler(FTP::splitOnIdle), NULL, this);

   pLeft = new wxPanel(split, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);

   sz5 = new wxBoxSizer(wxVERTICAL);

   lPath = new wxComboBox( pLeft, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxSTATIC_BORDER|wxTE_PROCESS_ENTER  );
   sz5->Add( lPath, 0, wxEXPAND|wxTOP|wxLEFT, 5 );

   lList = new Qlist( pLeft);
   lList->SetName("L");

   sz5->Add(lList, 1, wxEXPAND|wxTOP|wxBOTTOM|wxLEFT, 5);

   wxFileName::SetCwd( ::wxGetUserHome() );

   pLeft->SetSizer(sz5);
   pLeft->Layout();
   sz5->Fit( pLeft );

   pRight = new wxPanel(split, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);

   sz6 = new wxBoxSizer(wxVERTICAL);

   rPath = new wxComboBox(pRight, wxID_ANY, _("Remote Directory List - Not Connected"), wxDefaultPosition, wxDefaultSize, 0, NULL, wxSTATIC_BORDER|wxTE_PROCESS_ENTER );

   sz6->Add(rPath, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5);

   rList = new Qlist(pRight);
   rList->SetName("R");

   sz6->Add(rList, 1, wxEXPAND|wxTOP|wxBOTTOM|wxRIGHT|wxLEFT, 5);

   pRight->SetSizer(sz6);
   pRight->Layout();
   sz6->Fit(pRight);
   split->SplitVertically(pLeft, pRight, 0);
   split->Unsplit(pLeft);

   sz4->Add(split, 1, wxEXPAND, 5);
   this->SetSizer(sz4);
   this->Layout();
   sz4->Fit(this);

   lPath->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( FTP::lPathOnTextEnter ), NULL, this);
   rPath->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( FTP::rPathOnTextEnter ), NULL, this);
 }

 FTP::~FTP()
 {

 }

 void
  FTP::lPathOnTextEnter( wxCommandEvent& WXUNUSED(e) )
 {
/*
  if ( wxFileName::DirExists( lPath->GetValue() ) )
  {
    wxFileName::SetCwd( lPath->GetValue() );
    wxGetApp().m_frame->update_local_list();
  }
*/
 }

 void
  FTP::rPathOnTextEnter( wxCommandEvent& WXUNUSED(e) )
 {
/*
  connection *c = (connection *) &clist[active];
  int nQueue;

  if ( c->m_state ) {

	nQueue = ((wxArrayString *)(c->m_queue))->GetCount();

	if (rPath->GetValue().Len()) {
     ((wxArrayString *)(c->m_queue))->Add("CWD " + rPath->GetValue().GetData());
	 ((wxArrayString *)(c->m_queue))->Add("PWD");
	 ((wxArrayString *)(c->m_queue))->Add("LIST");
	}
	else {
	 ((wxArrayString *)(c->m_queue))->Add("PWD");
	 ((wxArrayString *)(c->m_queue))->Add("LIST");
	}

    if ( (c->m_state == 11) && !nQueue )
     state_machine_ftp( '0', c );
  }
*/
 }

 char
  FTP::read_ftp_cc (connection *c)
 {
   char tt[5] = { 0 }, p[ (1024*4) + 2 ] = { 0 };
   int  r = 0;

   while (true) {

    r = c->recv_data(p + strlen(p) , 1, 0 );

    if ( r == 0 || r == -1 ) {
      logit_a ("read_ftp_cc c %x %d\n", c, r);
      return (char)r;
    }

    if ( !tt[0] && p[3] ) {
      if ( p[3] == ' ' ) 
        strcat( tt, "\r\n" );
      else if ( p[3] == '-' )
        memmove( tt, p, 3 ) , tt[3] = ' ';
    }

    if ( tt[0] && !( memcmp( p + strlen( p ) - strlen( tt ) , tt, strlen( tt ) ) ) )  { 

     if (! memcmp( p + strlen( p ) - strlen( tt ) , "\r\n", 2 ))
       break;
     else
      sprintf( tt, "%s", "\r\n");
    }
   } /* while */

   OutputDebugStringA (p);

   r = ( *(p+0) - '0' ) * 100 + ( *(p+1) - '0' ) * 10 + *(p+2) - '0';
 
   if ( r == 227 ) {  /* (170,225,15,40,148,53) */ 

    int h1, h2, h3, h4, p1, p2;

    sscanf( strchr( p, '(' ) + 1, "%d,%d,%d,%d,%d,%d", &h1, &h2, &h3, &h4, &p1, &p2 );

    //sprintf ( c->d_host, "%d.%d.%d.%d", h1, h2, h3, h4 );
    //sprintf ( c->d_port, "%d", ( p1 << 8 ) + p2 );

   } 

   return *p;
 }

 int
  read_ftp_dc(connection *c)
 {
   char buf[4096*2] = { 0 };
   int  r = 0;

   r = c->recv_data(buf , sizeof(buf), 0 );

   logit_a ("dc recv c %x: %d bytes\n", c, r);
	
   if (c->m_protocol == PROTO_FTP_DC) {

     /* directory listing */

   } else {

     /* file data */

   }

   return r;
 }

 int
  new_cmd (connection * c, const char *cmd, const char *arg ) 
 {
   char buf[1024];

   buf[0] = '\0';

   strcat(buf, cmd);

   if ( ( arg != 0 ) && ( strlen( arg ) < 1024 ) ) {
     strcat( buf, " " );
     strcat( buf, arg );
   }

   strcat( buf, "\r\n" );

   logit_a ("%s", buf);

   return c->send_data(buf, strlen(buf) );
 }

 /* preprocess ftp connections before calling state_machine */

 void
  process_ftp (connection *c)
 {
   assert(c);

   if (c->m_protocol == 1) { /* CC */

     state_machine (c);

   } else if (c->m_protocol > 1) { /* proto_ftps_dc */

     assert(c->m_protocol <= 4);

     int len = read_ftp_dc(c);

     if (!len || len == -1) {

       logit_a ("%s: cleaning dc connection %x\n", __func__, c);

       c->m_state = 0,

     #ifdef _WIN32
       shutdown(c->m_sd, 2);
       closesocket(c->m_sd);
     #else
       shutdown( c->m_sd, SHUT_RDWR );
       close(c->m_sd);
     #endif
       memset(c, 0, sizeof(connection));
     }
   } else {
      assert(0);
   }

 }

 void
  NP::ftp_state_machine (wxCommandEvent& e)
 {
   wxMutexLocker lock(*m_mutex);

   int code = e.GetInt();

   connection *c = (connection *) e.GetClientData();
/*
    if(cc)
     int code = read_ftp_cc (c);
*/
   logit_a ("%s(%d): c %x, m_state %x code %c primary %d\n", __func__, GetCurrentThreadId(), c, c->m_state, code, c->isPrimary);

   switch (c->m_state)
   {
     case 1:
     {
       if (code <= '3') {

         c->m_state++;

         new_cmd (c, "AUTH", "TLS");

       } else {

         c->m_state = -1;

       }

       break;
     }

     case 2:
     {
       c->m_state++;

       if (code <= '3') {

          /* AUTH  successful; server accepts TLS */ 

          /* do handshake and stuff */

       } else {

          /* no TLS support; proceed anyways */

          new_cmd (c, "USER", ((wxString *)c->m_user)->mb_str());

       }

       break;
     }

     case 3:
     {
       if (code <= '3') {

         c->m_state++;

         new_cmd (c, "PASS", ((wxString *)c->m_password)->mb_str());

       }

       break;
     }

     case 4:
     {
       if (code <= '3') {

          c->m_state++;

          new_cmd (c, "SYST", 0);

       } else {

          c->m_state = -1;

          new_cmd (c, "QUIT", 0);

       }

       break;
     }

     case 5:
     {
       c->m_state++;

       ((FTP *)p2)->rPath->SetValue("");

       new_cmd (c, "PWD", 0 );

       break;
     }

       case 6:
       case 7:
       {

         break;
       }

       case 8:
       {
         if (code <= '3') {
           c->m_state++;
           new_cmd (c, "PASV", 0 );
         }
         break;
       }

       case 9:
       {
         c->m_state++;


         break;
       }

       case 10:
       {
         c->m_state++;
         break;
       }

       case 11:
       {

         break;
       }

       case 12:
       {

         break;
       }

       case 13:
       {

         break;
       }

       default:
       {
         logit_a ("%s < c %x, m_state [%x] default hit\n", __func__, c, c->m_state);
         break;
       }
   }
  
   logit_a ("%s < c %x, m_state [%x] code %c\n", __func__, c, c->m_state, code);

   if (lock.IsOk()) {

     m_condition->Broadcast();

   } else {
     logit_a ("%s(%d): lock.IsOk failed\n", __func__, GetCurrentThreadId());
   }
}
